using System;
using System.Management.Automation;
using System.Text;
using Nivot.PowerShell.WindowsMobile.Rapi2;

namespace Nivot.PowerShell.WindowsMobile
{
    public abstract class CEObject
    {        
        private readonly RemoteDevice _device;
        private readonly string _path;
        protected readonly string Separator = Provider.ProviderInfo.PathSeparator.ToString();
        private CEFileAttributes? _attributes;
        private string _mode = null;

        protected CEObject(RemoteDevice device, string fullPath)
        {
            _device = device;

            if (!fullPath.StartsWith(Separator))
            {
                fullPath = Separator + fullPath;
            }
            _path = fullPath;            
        }

        public virtual string FullPath
        {
            get { return _path; }
        }

        public abstract string Name { get; }

        public virtual DateTime? LastWriteTime
        {
            get { return Device.GetFileLastWriteTime(this.FullPath); }
        }

        public virtual string Mode
        {
            get
            {
                EnsureMode();
                return _mode;
            }
        }

        public virtual CEFileAttributes Attributes
        {
            get
            {
                EnsureAttributes();
                return _attributes.Value;
            }
            set
            {
                try
                {
                    Device.SetFileAttributes(this.FullPath, value);
                    _attributes = null; // reset cache
                }
                catch (RapiException ex)
                {
                    var record = new ErrorRecord(ex, "ErrorSetAttrib", ErrorCategory.WriteError, value);
                    Provider.WriteError(record);
                }
            }
        }

        /// <summary>
        /// Gets the current StoreProviderBase derived provider that is utilising this object.
        /// <remarks>Use this member to invoke WriteVerbose, WriteDebug and other instance methods on the active provider instance in a thread-safe manner.</remarks>
        /// </summary>
        protected static WindowsMobileProvider Provider
        {
            get { return (WindowsMobileProvider) StoreProviderContext.Current; }
        }

        protected RemoteDevice Device
        {
            get { return _device; }
        }

        private void EnsureAttributes()
        {
            if (_attributes == null)
            {
                _attributes = Device.GetFileAttributes(this.FullPath);
            }
        }

        private void EnsureMode()
        {
            var builder = new StringBuilder();

            if ((this.Attributes & CEFileAttributes.Directory) == CEFileAttributes.Directory)
            {
                builder.Append("d");
            }
            else
            {
                builder.Append("-");
            }
            if ((this.Attributes & CEFileAttributes.Archive) == CEFileAttributes.Archive)
            {
                builder.Append("a");
            }
            else
            {
                builder.Append("-");
            }
            if ((this.Attributes & CEFileAttributes.ReadOnly) == CEFileAttributes.ReadOnly)
            {
                builder.Append("r");
            }
            else
            {
                builder.Append("-");
            }
            if ((this.Attributes & CEFileAttributes.Hidden) == CEFileAttributes.Hidden)
            {
                builder.Append("h");
            }
            else
            {
                builder.Append("-");
            }
            if ((this.Attributes & CEFileAttributes.System) == CEFileAttributes.System)
            {
                builder.Append("s");
            }
            else
            {
                builder.Append("-");
            }
            if ((this.Attributes & CEFileAttributes.InRom) == CEFileAttributes.InRom)
            {
                builder.Append("i");
            }
            else
            {
                builder.Append("-");
            }
            if ((this.Attributes & CEFileAttributes.RomModule) == CEFileAttributes.RomModule)
            {
                builder.Append("m");
            }
            else
            {
                builder.Append("-");
            }
            _mode = builder.ToString();
        }

        public override string ToString()
        {
            return this.FullPath;
        }
    }
}